//
//  NSArray+TFCore.m
//  TFFoundation
//
//  Created by TFAppleWork-Summer on 2017/3/8.
//  Copyright © 2017年 TFAppleWork-Summer. All rights reserved.
//

#import "NSArray+TFCore.h"

@implementation NSArray (TFCore)

#pragma mark - 数据越界预处理读取和快捷读取转换

- (id)tf_objectAtIndex:(NSInteger)index {
    return (index < self.count && index >= 0) ? self[index] : nil;
}

- (NSString *)tf_stringAtIndex:(NSInteger)index {
    id value = [self tf_objectAtIndex:index];
    if (value == nil || value == [NSNull null] || [[value description] isEqualToString:@"<null>"])
    {
        return nil;
    }
    else if ([value isKindOfClass:[NSString class]]) {
        return (NSString*)value;
    }
    else if ([value isKindOfClass:[NSNumber class]]) {
        return [value stringValue];
    }
    return nil;
}

- (NSNumber *)tf_numberAtIndex:(NSInteger)index withNumberStyle:(NSNumberFormatterStyle)numberStyle {
    id value = [self tf_objectAtIndex:index];
    if ([value isKindOfClass:[NSNumber class]]) {
        return value;
    }
    else if ([value isKindOfClass:[NSString class]]) {
        NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
        formatter.numberStyle = numberStyle;
        return [formatter numberFromString:value];
    }
    return nil;
}

- (NSInteger)tf_integerWithIndex:(NSInteger)index {
    id value = [self tf_objectAtIndex:index];
    if (value == nil || value == [NSNull null])
    {
        return 0;
    }
    if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]])
    {
        return [value integerValue];
    }
    return 0;
}

- (BOOL)tf_boolWithIndex:(NSInteger)index {
    id value = [self tf_objectAtIndex:index];
    if (value == nil || value == [NSNull null])
    {
        return NO;
    }
    if ([value isKindOfClass:[NSNumber class]])
    {
        return [value boolValue];
    }
    if ([value isKindOfClass:[NSString class]])
    {
        return [value boolValue];
    }
    return NO;
}

- (float)tf_floatWithIndex:(NSInteger)index {
    id value = [self tf_objectAtIndex:index];
    if (value == nil || value == [NSNull null])
    {
        return 0.0;
    }
    if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]])
    {
        return [value floatValue];
    }
    return 0.0;
}

- (double)tf_doubleWithIndex:(NSInteger)index {
    id value = [self tf_objectAtIndex:index];
    if (value == nil || value == [NSNull null])
    {
        return 0.0;
    }
    if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]])
    {
        return [value doubleValue];
    }
    return 0.0;
}

#pragma mark - 快速处理数据方法--包含筛选、匹配、排序等等。

- (void)tf_enumerateUsingBlock:(TFArrayEnumerateBlock)block {
    [self tf_enumerateWithOptions:TFArrayEnumerateTraverse usingBlock:block];
}

- (void)tf_enumerateWithOptions:(TFArrayEnumerateOptions)options usingBlock:(TFArrayEnumerateBlock)block {
    switch (options) {
            case TFArrayEnumerateTraverse:
        {
            [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                block(obj,idx);
            }];
        }
            break;
            case TFArrayEnumerateReverse: case TFArrayEnumerateConcurrent: {
                NSEnumerationOptions enumerateOption = NSEnumerationReverse;
                if (options==TFArrayEnumerateConcurrent) {
                    enumerateOption = NSEnumerationConcurrent;
                }
                [self enumerateObjectsWithOptions:enumerateOption usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    block(obj,idx);
                }];
            }
            break;
        default:
            break;
    }
}

- (NSArray *)tf_mapUsingBlock:(TFArrayMapBlock)block {
    return [self tf_mapWithOptions:TFArrayEnumerateTraverse usingBlock:block];
}

- (NSArray *)tf_mapWithOptions:(TFArrayEnumerateOptions)options usingBlock:(nonnull TFArrayMapBlock)block {
    NSMutableArray *mapArray = [NSMutableArray array];
    [self tf_enumerateWithOptions:options usingBlock:^(id  _Nonnull obj, NSInteger idx) {
        id newObj = block(obj,idx);
        if (newObj) {
            [mapArray addObject:newObj];
        }
        else {
            [mapArray addObject:[NSNull null]];
        }
    }];
    return [NSArray arrayWithArray:mapArray];
}

- (id)tf_reduceWithInitialValue:(id)initialValue usingBlock:(nullable TFArrayReduceBlock)block {
    return [self tf_reduceWithInitialValue:initialValue option:TFArrayEnumerateTraverse usingBlock:block];
}

- (id)tf_reduceWithInitialValue:(id)initialValue option:(TFArrayEnumerateOptions)option usingBlock:(TFArrayReduceBlock)block {
    __block id result = initialValue;
    [self tf_enumerateWithOptions:option usingBlock:^(id  _Nonnull obj, NSInteger idx) {
        result = block(result,obj,idx);
    }];
    return result;
}

- (id)tf_matchObjectWithPredicateBlock:(TFArrayPredicateBlock)predicateBlock {
    NSInteger index = [self indexOfObjectPassingTest:^BOOL(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        return predicateBlock(obj,idx);
    }];
    return [self tf_objectAtIndex:index];
}

- (id)tf_matchObjectWithOptions:(NSEnumerationOptions)options predicateBlock:(nonnull TFArrayPredicateBlock)predicateBlock {
    NSInteger index = [self indexOfObjectWithOptions:options passingTest:^BOOL(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        return predicateBlock(obj,idx);
    }];
   return [self tf_objectAtIndex:index];
}

- (BOOL)tf_anyWithPredicateBlock:(TFArrayPredicateBlock)predicateBlock {
    return ([self tf_matchObjectWithPredicateBlock:predicateBlock]!=nil);
}

- (BOOL)tf_noneWithPredicateBlock:(TFArrayPredicateBlock)predicateBlock {
    return ([self tf_matchObjectWithPredicateBlock:predicateBlock]==nil);
}

- (BOOL)tf_allWithPredicateBlock:(TFArrayPredicateBlock)predicateBlock {
    __block BOOL result = YES;
    [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (!predicateBlock(obj,idx)) {
            result = NO;
            *stop = YES;
        }
    }];
    return result;
}

- (BOOL)tf_compareWithArray:(NSArray *)array usingblock:(TFArrayCompareBlock)block {
    __block BOOL result = NO;
    [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (idx < array.count) {
            id obj2 = array[idx];
            result = block(obj,obj2,idx);
        }
        else {
            result = NO;
        }
        *stop = !result;
    }];
    return result;
}

- (NSArray *)tf_filteredWithPredicateBlock:(TFArrayPredicateBlock)predicateBlock {
    typeof(self) __weak weakSelf = self;
    
    return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
        return predicateBlock(evaluatedObject,[weakSelf indexOfObject:evaluatedObject]);
    }]];
}

- (NSArray *)tf_filteredWithPredicateFormat:(NSString *)predicateFormat, ... {
    va_list args;
    va_start(args, predicateFormat);
    predicateFormat = [[NSString alloc] initWithFormat:predicateFormat arguments:args];
    va_end(args);
    return [self filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:predicateFormat]];
}

- (NSArray *)tf_sortedArrayWithAscending:(BOOL)ascending {
    NSSortDescriptor *sortDesc = [NSSortDescriptor sortDescriptorWithKey:nil ascending:ascending];
    return [self sortedArrayUsingDescriptors:@[sortDesc]];
}

- (NSArray *)tf_sortedArrayWithDescriptorDic:(NSDictionary<NSString *,NSNumber *> *)descriptorDic {
    NSMutableArray *descripArray = @[].mutableCopy;
    [descriptorDic enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) {
        [descripArray addObject:[NSSortDescriptor sortDescriptorWithKey:key ascending:[obj boolValue]]];
    }];
    return [self sortedArrayUsingDescriptors:descripArray];
}

- (NSArray *)tf_removeObject:(id)object {
    NSMutableArray *array = [NSMutableArray arrayWithArray:self];
    [array removeObject:object];
    return [NSArray arrayWithArray:array];
}

- (NSArray *)tf_removeObjectAtIndex:(NSInteger)index {
    NSMutableArray *array = [NSMutableArray arrayWithArray:self];
    [array removeObjectAtIndex:index];
    return [NSArray arrayWithArray:array];
}

- (NSArray *)tf_removeFirstObject {
    return [self tf_removeObjectAtIndex:0];
}

- (NSArray *)tf_removeLastObject {
    return [self tf_removeObjectAtIndex:self.count-1];
}

- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
    return [self p_descriptionWithLevel:level];
}

- (NSString *)p_descriptionWithLevel:(NSUInteger)level {
    NSString *subSpace = [self p_getSpaceWithLevel:level];
    NSString *space = [self p_getSpaceWithLevel:level?level - 1:0];
    NSMutableString *retString = [[NSMutableString alloc] init];
    // 1、添加 [
    [retString appendString:[NSString stringWithFormat:@"["]];
    // 2、添加 value
    [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:[NSString class]]) {
            NSString *value = (NSString *)obj;
            value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            NSString *subString = [NSString stringWithFormat:@"\n%@\"%@\",", subSpace, value];
            [retString appendString:subString];
        } else if ([obj isKindOfClass:[NSArray class]]) {
            NSArray *arr = (NSArray *)obj;
            NSString *str = [arr p_descriptionWithLevel:level + 1];
            str = [NSString stringWithFormat:@"\n%@%@,", subSpace, str];
            [retString appendString:str];
        } else if ([obj isKindOfClass:[NSDictionary class]]) {
            NSDictionary *dic = (NSDictionary *)obj;
            NSString *str = [dic descriptionWithLocale:nil indent:level + 1];
            str = [NSString stringWithFormat:@"\n%@%@,", subSpace, str];
            [retString appendString:str];
        } else {
            NSString *subString = [NSString stringWithFormat:@"\n%@%@,", subSpace, obj];
            [retString appendString:subString];
        }
    }];
    if ([retString hasSuffix:@","]) {
        [retString deleteCharactersInRange:NSMakeRange(retString.length-1, 1)];
    }
    // 3、添加 ]
    [retString appendString:[NSString stringWithFormat:@"\n%@]", space]];
    return retString;
}

/**
 根据层级，返回前面的空格占位符
 
 @param level 字典的层级
 @return 占位空格
 */
- (NSString *)p_getSpaceWithLevel:(NSUInteger)level {
    NSMutableString *mustr = [[NSMutableString alloc] init];
    for (NSUInteger i=0; i<level; i++) {
        [mustr appendString:@"\t"];
    }
    return mustr;
}

@end
